package org.ilc.socketserver.codec;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.ilc.socketserver.Request;

/**
 * @author malongbo
 */
public class HttpProtocolDecoder implements IProtocolDecoder {
    private static final AttributeKey BUF_CONTEXT = new AttributeKey(
            HttpProtocolDecoder.class, "context");
    private static final AttributeKey HEADER_BUFFER = new AttributeKey (
            HttpProtocolDecoder.class, "headBuffer");
    private static final AttributeKey BODY_BUFFER = new AttributeKey (
            HttpProtocolDecoder.class, "bodyBuffer");

    /**
     * 头最大字节数 5KB
     */
    private final static int HEAD_MAX_LENGTH = 5 * 1024;

    @Override
    public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
        try {
            /*Context context = (Context) session.getAttribute(BUF_CONTEXT);
            while (in.hasRemaining()) {
                if (null == context) {
                    context = new Context ();
                }
                // 判断 头长度 避免 恶意 发送大数据包
                if (context.headLength() >= HEAD_MAX_LENGTH) {
                    throw new Exception("receive a large header");
                }

                // 如果已经接收完头
                if (context.matched) {
                    receiveContent(context, in, out, session);
                }

                if(!in.hasRemaining()){
                    break;
                }
                // 接收头
                byte b = in.get();
                switch (b) {
                    case '\r':
                        context.matcheCount = context.matcheCount + 1;
                        break;
                    case '\n':
                        context.matched = true && (context.matcheCount == 1);
                        break;
                    default:
                        context.matcheCount = 0;
                        break;
                }
                context.writeHead(b);
            }

            if (null != context) {
                if (context.matched) {
                    receiveContent(context, in, out, session);
                }
                session.setAttribute(BUF_CONTEXT, context);
            }*/

            Context context = (Context) session.getAttribute(BUF_CONTEXT);
            while (in.hasRemaining()) {
                if (null == context) {
                    context = new Context ();
                }
                // 判断 头长度 避免 恶意 发送大数据包
                if (context.headLength() >= HEAD_MAX_LENGTH) {
                    throw new Exception("receive a large header");
                }

                // 如果已经接收完头
                if (context.matched) {
                    receiveContent(context, in, out, session);
                }

                if(!in.hasRemaining()){
                    break;
                }
                // 接收头
                byte b = in.get();
                switch (b) {
                    case '\r':
                        context.matcheCount = context.matcheCount + 1;
                        break;
                    case '\n':
                        context.matched = true && (context.matcheCount == 1);
                        break;
                    default:
                        context.matcheCount = 0;
                        break;
                }
                context.writeHead(b);
            }

            if (null != context) {
                if (context.matched) {
                    receiveContent(context, in, out, session);
                }
                session.setAttribute(BUF_CONTEXT, context);
            }
        } catch (Exception ex) {
            session.setAttribute(BUF_CONTEXT, null);
            throw ex;
        } finally {

        }
    }

    /**
     *
     * @param context
     * @param in
     * @param out
     * @param session
     * @throws Exception
     */
    private void receiveContent(Context context, IoBuffer in,
                                ProtocolDecoderOutput out, IoSession session) throws Exception {
        /*int contentLenght = context.getHeader().getContentLength();
        // 0 表示无body
        if (contentLenght == 0) {
            writeData(out, context, session);
        } else {
            if(in.hasRemaining()){
                int currDataLength = in.remaining ();// 当前长度
//                int currDataLength = in.limit();// 当前长度
                // 当前已经接收的长度
                int currReceivedLength = context.bodyLength();
                // 还需要接收的长度
                int remainingLength = contentLenght - currReceivedLength;
                if (currDataLength >= remainingLength) {
                    byte[] body = new byte[remainingLength];
                    in.get(body);
                    context.writeBody(body);
                    // 接收完毕 输出
                    writeData(out, context, session);
                    body = null;
                } else {
                    byte[] body = new byte[currDataLength];
                    in.get(body);
                    context.writeBody(body);
                    body = null;
                }
            }
        }*/
        int contentLenght = context.getHeader().getContentLength();
        // 0 表示无body
        if (contentLenght == 0) {
            writeData(out, context, session);
        } else {
            if(in.hasRemaining()){
                int currDataLength = in.remaining ();// 当前长度
//                int currDataLength = in.limit();// 当前长度
                // 当前已经接收的长度
                int currReceivedLength = context.bodyLength();
                // 还需要接收的长度
                int remainingLength = contentLenght - currReceivedLength;
                if (currDataLength >= remainingLength) {
                    byte[] body = new byte[remainingLength];
                    in.get(body);
                    context.writeBody(body);
                    // 接收完毕 输出
                    writeData(out, context, session);
                    body = null;
                } else {
                    byte[] body = new byte[currDataLength];
                    in.get(body);
                    context.writeBody(body);
                    body = null;
                }
            }
        }
    }

    private void writeData(ProtocolDecoderOutput out, Context context, IoSession session)
            throws Exception {
        Request request = new Request ();
        byte [] headerBytes = context.getHeaderBytes ();
        byte [] bodyBytes = context.getBodyBytes ();
//        System.out.println ("header: " + new String (headerBytes));
//        System.out.println ("body: " + new String (bodyBytes));
        request.setHeaderData (headerBytes);

        request.setBody (bodyBytes);
        out.write (request);
        session.setAttribute (BUF_CONTEXT, null);
        context.destroy ();
//        context = null;

    }

}